package com.tuanzi.loan.web.domain;

import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.apache.commons.collections4.CollectionUtils;
import org.primefaces.model.DefaultTreeNode;
import org.primefaces.model.TreeNode;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.tuanzi.loan.business.entity.system.DataPermission;
import com.tuanzi.loan.business.entity.system.FunctionalPermission;
import com.tuanzi.loan.business.entity.system.Menu;
import com.tuanzi.loan.business.service.system.DataPermissionService;
import com.tuanzi.loan.business.service.system.FunctionalPermissionService;
import com.tuanzi.loan.core.util.SpringContextHolder;

/**
 * @author Ray 2017/09/21
 */
public class PermissionDomain {

    private FunctionalPermissionService functionalPermissionService = SpringContextHolder
            .getBean(FunctionalPermissionService.class);

    private DataPermissionService dataPermissionService = SpringContextHolder
            .getBean(DataPermissionService.class);

    private List<String> persistedFunctionalPermissionIds;
    private List<String> persistedDataPermissionIds;

    public PermissionDomain() {
        persistedFunctionalPermissionIds = Lists.newArrayList();
        persistedDataPermissionIds = Lists.newArrayList();
    }

    public PermissionDomain(List<String> persistedFunctionalPermissionIds,
            List<String> persistedDataPermissionIds) {
        this.persistedFunctionalPermissionIds = persistedFunctionalPermissionIds;
        this.persistedDataPermissionIds = persistedDataPermissionIds;
    }

    public TreeNode generateDataPermissionTreeNode() {
        TreeNode treeNode = new DefaultTreeNode("Root", null);
        treeNode.setExpanded(true);
        TreeNode root = structureDataTreeRoot();
        treeNode.getChildren().add(root);

        final List<DataPermission> topDataPermissionMap = Lists.newArrayList();
        final Map<String/* parentId */, List<DataPermission>> subDataPermissionMap = Maps
                .newHashMap();
        for (DataPermission dataPermission : dataPermissionService.findAll()) {

            if (dataPermission.getParentId() == null) {
                topDataPermissionMap.add(dataPermission);
            } else {

                List<DataPermission> dataPermissions = subDataPermissionMap
                        .get(dataPermission.getParentId());
                if (dataPermissions == null) {
                    dataPermissions = Lists.newArrayList();
                }
                dataPermissions.add(dataPermission);
                subDataPermissionMap.put(dataPermission.getParentId(), dataPermissions);
            }
        }

        topDataPermissionMap.stream().sorted(Comparator.comparing(DataPermission::getName))
                .map(x -> this.generateDataPermissionTreeNode(x, subDataPermissionMap))
                .forEach(x -> root.getChildren().add(x));
        return treeNode;
    }

    public TreeNode generateFunctionalPermissionTreeNode() {
        TreeNode treeNode = new DefaultTreeNode("Root", null);
        treeNode.setExpanded(true);
        TreeNode root = structureFunctionalTreeRoot();
        treeNode.getChildren().add(root);

        final List<FunctionalPermission> topFunctionalPermissionMap = Lists.newArrayList();
        final Map<String/* parentId */, List<FunctionalPermission>> subFunctionalPermissionMap = Maps
                .newHashMap();
        for (FunctionalPermission functionalPermission : functionalPermissionService.findAll()) {

            if (functionalPermission.getParentId() == null) {
                topFunctionalPermissionMap.add(functionalPermission);
            } else {

                List<FunctionalPermission> functionalPermissions = subFunctionalPermissionMap
                        .get(functionalPermission.getParentId());
                if (functionalPermissions == null) {
                    functionalPermissions = Lists.newArrayList();
                }
                functionalPermissions.add(functionalPermission);
                subFunctionalPermissionMap.put(functionalPermission.getParentId(),
                        functionalPermissions);
            }
        }

        topFunctionalPermissionMap.stream()
                .sorted(Comparator.comparing(FunctionalPermission::getName))
                .map(x -> this.generateFunctionalPermissionTreeNode(x, subFunctionalPermissionMap))
                .forEach(x -> root.getChildren().add(x));
        return treeNode;
    }

    private TreeNode generateDataPermissionTreeNode(DataPermission dataPermission,
            Map<String/* parentId */, List<DataPermission>> subDataPermissionMap) {

        if (CollectionUtils.isEmpty(subDataPermissionMap.get(dataPermission.getId()))) {
            dataPermission.setIcon("fa fa-user-secret");

            if (persistedDataPermissionIds.contains(dataPermission.getId())) {
                return createSelectedTreeNode(dataPermission);
            } else {
                return createTreeNode(dataPermission);
            }
        }

        TreeNode branchTreeNode = null;
        dataPermission.setIcon("fa fa-folder-open");

        if (persistedDataPermissionIds.contains(dataPermission.getId())) {
            branchTreeNode = createSelectedTreeNode(dataPermission);
        } else {
            branchTreeNode = createTreeNode(dataPermission);
        }

        branchTreeNode.getChildren()
                .addAll(subDataPermissionMap.get(dataPermission.getId()).stream()
                        .sorted(Comparator.comparing(DataPermission::getName))
                        .map(x -> this.generateDataPermissionTreeNode(x, subDataPermissionMap))
                        .collect(Collectors.toList()));

        return branchTreeNode;
    }

    private TreeNode generateFunctionalPermissionTreeNode(FunctionalPermission functionalPermission,
            Map<String/* parentId */, List<FunctionalPermission>> subFunctionalPermissionMap) {

        if (CollectionUtils.isEmpty(subFunctionalPermissionMap.get(functionalPermission.getId()))) {
            functionalPermission.setIcon("fa fa-user-secret");

            if (persistedFunctionalPermissionIds.contains(functionalPermission.getId())) {
                return createSelectedTreeNode(functionalPermission);
            } else {
                return createTreeNode(functionalPermission);
            }
        }

        TreeNode branchTreeNode = null;
        functionalPermission.setIcon("fa fa-folder-open");

        if (persistedFunctionalPermissionIds.contains(functionalPermission.getId())) {
            branchTreeNode = createSelectedTreeNode(functionalPermission);
        } else {
            branchTreeNode = createTreeNode(functionalPermission);
        }

        branchTreeNode.getChildren().addAll(subFunctionalPermissionMap
                .get(functionalPermission.getId()).stream()
                .sorted(Comparator.comparing(FunctionalPermission::getName))
                .map(x -> this.generateFunctionalPermissionTreeNode(x, subFunctionalPermissionMap))
                .collect(Collectors.toList()));

        return branchTreeNode;
    }

    private TreeNode createSelectedTreeNode(Object data) {
        TreeNode treeNode = createTreeNode(data);
        treeNode.setSelected(true);
        return treeNode;
    }

    private TreeNode createTreeNode(Object data) {
        TreeNode treeNode = new DefaultTreeNode(data);
        return treeNode;
    }

    private TreeNode createTreeRootNode(Object data) {
        TreeNode treeNode = new DefaultTreeNode(data);
        treeNode.setExpanded(true);
        return treeNode;
    }

    private TreeNode structureFunctionalTreeRoot() {
        FunctionalPermission rootPermission = new FunctionalPermission();
        rootPermission.setName("菠萝天眼");
        rootPermission.setIcon("fa fa-yen");
        rootPermission.setEnable(true);
        return createTreeRootNode(rootPermission);
    }

    private TreeNode structureDataTreeRoot() {
        DataPermission rootPermission = new DataPermission();
        rootPermission.setName("菠萝天眼");
        rootPermission.setIcon("fa fa-yen");
        rootPermission.setEnable(true);
        return createTreeRootNode(rootPermission);
    }

    public Menu generateMenu() {
        return null;
    }

}
